#include "RingQueue.hpp"
#include "Thread.hpp"
#include "Task.hpp"
#include <string>
#include <vector>
#include <unistd.h>
#include <ctime>

using namespace ThreadModule;
using ringqueue_t = RingQueue<Task>;

void InitCom(std::vector<Thread<ringqueue_t>> *threads, int num, ringqueue_t &rq,
 func_t<ringqueue_t> func, const std::string who)
{
    for(int i=0;i<num;++i)
    {
        std::string thread_name="Thread-"+std::to_string(i+1)+"-"+who;
        
        threads->emplace_back(func,rq,thread_name);
    }
}

void Producer(ringqueue_t& rq, std::string name)
{
    srand(time(nullptr)^pthread_self());

    while(true)
    {
        rq.Enqueue(Download);
        std::cout<<"Producer:"<<"["<<name<<"]"<<std::endl;
    
    }
}


void Consumer(ringqueue_t& rq, std::string name)
{
    while(true)
    {
        sleep(2);

        Task t;
        rq.Pop(&t);
        std::cout<<"Consumer handle task:"<<"["<<name<<"]"<<std::endl;
        t();
    }
}



void InitProducer(std::vector<Thread<ringqueue_t>> *threads, int num, ringqueue_t &rq)
{
   
    InitCom(threads, num, rq, Producer, "Producer");
}


void InitConsumer(std::vector<Thread<ringqueue_t>>* threads, int num, ringqueue_t& rq)
{
   
    InitCom(threads, num, rq, Consumer, "Consumer");
}

void StarAllThread(std::vector<Thread<ringqueue_t>>& threads)
{
    for(auto& t:threads)
    {
        std::cout<<"Thread:"<<t.name()<<" is running"<<std::endl;
        t.Start();
    }
}


void WaitAllThread(std::vector<Thread<ringqueue_t>>& threads)
{
    for(auto& t:threads)
    {
        t.Join();
    }
}

int main()
{
    ringqueue_t* rq=new ringqueue_t(10);
    std::vector<Thread<ringqueue_t>> threads;

    InitProducer(&threads,1,*rq);
    InitConsumer(&threads,1,*rq);


    StarAllThread(threads);
    WaitAllThread(threads);
    return 0;
}

